AWSの構成図をChatGPT(GPT-4V)に読み込ませてIaCコードを生成してみた
こんにちは、つくぼし(tsukuboshi0755)です!
最近ChatGPTがGPT-4Vを発表し、AI業界がさらに盛り上がりを見せてますね。
GPT-4Vを用いる事で、ChatGPTがユーザ側から入力された画像を読み取った上で、応答を返してくれるようになります。
この機能追加により、なんと以下のようにAWSの構成図を読み取って、IaCコードを生成できる事が話題になっていました。
本日をもって引退します pic.twitter.com/fygAQDQ5kj
— 電気ひつじ(onoteru) (@teru0x1) October 13, 2023
これを見て私もGPT-4Vを試してみたくなったので、今回はChatGPTを使って、様々なAWSの構成図を入力し、どこまで正確にIaCコードを生成できるか確認してみます!
GPT-4Vを利用する際の注意点
先にGPT-4Vを利用してAWS構成図からIaCコードを生成する場合に関して、注意点を以下の通り明示しておきます。
- 現状GPT-4Vを利用するには、有料プラン(ChatGPT Plus)の加入が必要になります。
-
構成図に記載されていないリソースについては、ChatGPTが一部補完してくれる場合もありますが、補完されない場合もあります。構成図上に記載されていないリソースについても確実にIaCコードに含めたい場合、構成図に該当のリソースを追加するか、ユーザ側から該当のリソース情報を追加で補足する必要があります。
-
ChatGPTには文字数(トークン)制限があり、IaCコードの量が膨大な場合、返答の途中でエラーが発生する事があります。その場合、ユーザ側で「コードは3000トークンを超えたら分割し、私が『続き』と入力したら続きの回答を投稿してください」というような文言を追加すると、ChatGPTがいい感じにコードを分割した上で返答してくれます。
-
ChatGPTは現状2022年1月までのデータしかアクセスできません。そのため2022年1月より後のAWSアップデートで追加・変更・削除された設定を反映できない事に注意してください。
-
ChatGPTで生成されるIaCコードは、AWS上で動作保証されているわけではありません。そのためもし生成されたIaCコードを使用したい場合は、事前に想定通り動作するか検証する事を推奨します。
パターン①:Web3層構成図をCloudFormationに変換
まずは構成図をCloudFormationに変換できるか試してみます。
質問内容
以下のようなWeb3層構成図とメッセージをGPT-4に質問した際に、どのようなCloudFormationコードが返ってくるか確認してみます。
- 構成図
- メッセージ
この構成図をデプロイするCloudFormationコードを作成してください。ただし、テンプレートは3000トークンを超えたら分割し、私が「続き」と入力したら続きの回答を投稿してください。
GPT-4からの返答
GPT-4からの返答で提供されたコードについて、以下に完全な形で示します。
CloudFormationコード
AWSTemplateFormatVersion: '2010-09-09' Description: 'AWS VPC with ALB, EC2 and RDS' Resources: # VPC VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: '10.0.0.0/16' EnableDnsSupport: 'true' EnableDnsHostnames: 'true' Tags: - Key: Name Value: VPC # Internet Gateway InternetGateway: Type: 'AWS::EC2::InternetGateway' Properties: Tags: - Key: Name Value: InternetGateway VPCGatewayAttachment: Type: 'AWS::EC2::VPCGatewayAttachment' Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # Public Subnets PublicSubnetA: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.1.0/24' MapPublicIpOnLaunch: 'true' AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: - Key: Name Value: PublicSubnetA PublicSubnetC: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.3.0/24' MapPublicIpOnLaunch: 'true' AvailabilityZone: !Select [ 1, !GetAZs '' ] Tags: - Key: Name Value: PublicSubnetC # Private Subnets PrivateSubnetA1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.2.0/24' AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: - Key: Name Value: PrivateSubnetA1 PrivateSubnetC1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.4.0/24' AvailabilityZone: !Select [ 1, !GetAZs '' ] Tags: - Key: Name Value: PrivateSubnetC1 # Elastic IPs for NAT Gateways EIPForNATGatewayA: Type: 'AWS::EC2::EIP' EIPForNATGatewayC: Type: 'AWS::EC2::EIP' # NAT Gateways NATGatewayA: Type: 'AWS::EC2::NatGateway' Properties: AllocationId: !GetAtt EIPForNATGatewayA.AllocationId SubnetId: !Ref PublicSubnetA NATGatewayC: Type: 'AWS::EC2::NatGateway' Properties: AllocationId: !GetAtt EIPForNATGatewayC.AllocationId SubnetId: !Ref PublicSubnetC # ALB Security Group ALBSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'ALB security group' VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: '80' ToPort: '80' CidrIp: '0.0.0.0/0' # ALB ApplicationLoadBalancer: Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' Properties: Scheme: 'internet-facing' Subnets: - !Ref PublicSubnetA - !Ref PublicSubnetC SecurityGroups: - !Ref ALBSecurityGroup Type: 'application' # ALB Listener ALBListener: Type: 'AWS::ElasticLoadBalancingV2::Listener' Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP # ALB Target Group ALBTargetGroup: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: VpcId: !Ref VPC Port: 80 Protocol: HTTP TargetType: instance # EC2 Security Group EC2SecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'EC2 security group' VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: '80' ToPort: '80' SourceSecurityGroupId: !Ref ALBSecurityGroup # EC2 Instance EC2InstanceA: Type: 'AWS::EC2::Instance' Properties: AvailabilityZone: !Select [ 0, !GetAZs '' ] InstanceType: t2.micro ImageId: 'ami-xxxxxx' # Please replace with a valid AMI ID SubnetId: !Ref PrivateSubnetA1 SecurityGroupIds: - !Ref EC2SecurityGroup KeyName: YourKeyName # Please replace with your key name EC2InstanceC: Type: 'AWS::EC2::Instance' Properties: AvailabilityZone: !Select [ 1, !GetAZs '' ] InstanceType: t2.micro ImageId: 'ami-xxxxxx' # Please replace with a valid AMI ID SubnetId: !Ref PrivateSubnetC1 SecurityGroupIds: - !Ref EC2SecurityGroup KeyName: YourKeyName # Please replace with your key name # RDS Security Group RDSSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref VPC GroupDescription: 'RDS security group' SecurityGroupIngress: - IpProtocol: tcp FromPort: '3306' ToPort: '3306' SourceSecurityGroupId: !Ref EC2SecurityGroup # RDS Subnet Group RDSSubnetGroup: Type: 'AWS::RDS::DBSubnetGroup' Properties: DBSubnetGroupDescription: 'RDS Subnet Group' SubnetIds: - !Ref PrivateSubnetA1 - !Ref PrivateSubnetC1 # RDS Instance RDSInstance: Type: 'AWS::RDS::DBInstance' Properties: AllocatedStorage: '20' DBInstanceClass: 'db.t2.micro' Engine: 'MySQL' MasterUsername: 'admin' MasterUserPassword: 'Password123' # Please replace with a secure password VPCSecurityGroups: - !Ref RDSSecurityGroup DBSubnetGroupName: !Ref RDSSubnetGroup MultiAZ: 'true' EngineVersion: '5.7' PubliclyAccessible: 'false'
コード検証
返答されたCloudFormationコードについて、実際にAWS上でデプロイできるか確認します。
この場合ではGPT-4のコメントでも明示されている通り、ImageId
とKeyName
を適切な値に置き換えます。
CloudFormationコード(修正後)
AWSTemplateFormatVersion: '2010-09-09' Description: 'AWS VPC with ALB, EC2 and RDS' Resources: # VPC VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: '10.0.0.0/16' EnableDnsSupport: 'true' EnableDnsHostnames: 'true' Tags: - Key: Name Value: VPC # Internet Gateway InternetGateway: Type: 'AWS::EC2::InternetGateway' Properties: Tags: - Key: Name Value: InternetGateway VPCGatewayAttachment: Type: 'AWS::EC2::VPCGatewayAttachment' Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway # Public Subnets PublicSubnetA: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.1.0/24' MapPublicIpOnLaunch: 'true' AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: - Key: Name Value: PublicSubnetA PublicSubnetC: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.3.0/24' MapPublicIpOnLaunch: 'true' AvailabilityZone: !Select [ 1, !GetAZs '' ] Tags: - Key: Name Value: PublicSubnetC # Private Subnets PrivateSubnetA1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.2.0/24' AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: - Key: Name Value: PrivateSubnetA1 PrivateSubnetC1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref VPC CidrBlock: '10.0.4.0/24' AvailabilityZone: !Select [ 1, !GetAZs '' ] Tags: - Key: Name Value: PrivateSubnetC1 # Elastic IPs for NAT Gateways EIPForNATGatewayA: Type: 'AWS::EC2::EIP' EIPForNATGatewayC: Type: 'AWS::EC2::EIP' # NAT Gateways NATGatewayA: Type: 'AWS::EC2::NatGateway' Properties: AllocationId: !GetAtt EIPForNATGatewayA.AllocationId SubnetId: !Ref PublicSubnetA NATGatewayC: Type: 'AWS::EC2::NatGateway' Properties: AllocationId: !GetAtt EIPForNATGatewayC.AllocationId SubnetId: !Ref PublicSubnetC # ALB Security Group ALBSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'ALB security group' VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: '80' ToPort: '80' CidrIp: '0.0.0.0/0' # ALB ApplicationLoadBalancer: Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' Properties: Scheme: 'internet-facing' Subnets: - !Ref PublicSubnetA - !Ref PublicSubnetC SecurityGroups: - !Ref ALBSecurityGroup Type: 'application' # ALB Listener ALBListener: Type: 'AWS::ElasticLoadBalancingV2::Listener' Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP # ALB Target Group ALBTargetGroup: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: VpcId: !Ref VPC Port: 80 Protocol: HTTP TargetType: instance # EC2 Security Group EC2SecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'EC2 security group' VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: '80' ToPort: '80' SourceSecurityGroupId: !Ref ALBSecurityGroup # EC2 Instance EC2InstanceA: Type: 'AWS::EC2::Instance' Properties: AvailabilityZone: !Select [ 0, !GetAZs '' ] InstanceType: t2.micro ImageId: 'ami-0fd8f5842685ca887' # Amazon Linux 2023のAMI IDを指定 SubnetId: !Ref PrivateSubnetA1 SecurityGroupIds: - !Ref EC2SecurityGroup KeyName: 'tsukuboshi-test-keypair' # 作成済みのキーペアを指定 EC2InstanceC: Type: 'AWS::EC2::Instance' Properties: AvailabilityZone: !Select [ 1, !GetAZs '' ] InstanceType: t2.micro ImageId: 'ami-0fd8f5842685ca887' # Amazon Linux 2023のAMI IDを指定 SubnetId: !Ref PrivateSubnetC1 SecurityGroupIds: - !Ref EC2SecurityGroup KeyName: 'tsukuboshi-test-keypair' # 作成済みのキーペアを指定 # RDS Security Group RDSSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: VpcId: !Ref VPC GroupDescription: 'RDS security group' SecurityGroupIngress: - IpProtocol: tcp FromPort: '3306' ToPort: '3306' SourceSecurityGroupId: !Ref EC2SecurityGroup # RDS Subnet Group RDSSubnetGroup: Type: 'AWS::RDS::DBSubnetGroup' Properties: DBSubnetGroupDescription: 'RDS Subnet Group' SubnetIds: - !Ref PrivateSubnetA1 - !Ref PrivateSubnetC1 # RDS Instance RDSInstance: Type: 'AWS::RDS::DBInstance' Properties: AllocatedStorage: '20' DBInstanceClass: 'db.t2.micro' Engine: 'MySQL' MasterUsername: 'admin' MasterUserPassword: 'Password123' # Please replace with a secure password VPCSecurityGroups: - !Ref RDSSecurityGroup DBSubnetGroupName: !Ref RDSSubnetGroup MultiAZ: 'true' EngineVersion: '5.7' PubliclyAccessible: 'false'
このCloudFormationコードをデプロイした結果をコンソールで確認すると、想定通りのリソースが作成されている事が分かります。
この場合はかなり想定通りにIaCコードを生成してくれたように感じました!
パターン②:静的Webサイトホスティング構成図をTerraformに変換
次に構成図をTerraformに変換できるか試してみます。
質問内容
以下のような静的Webサイトホスティング構成図とメッセージをGPT-4に流した際に、どのようなTerraformコードが返ってくるか確認してみます。
- 構成図
- メッセージ
この構成図をデプロイするTerraformコードを作成してください。ただし、テンプレートは3000トークンを超えたら分割し、私が「続き」と入力したら続きの回答を投稿してください。
GPT-4からの返答
GPT-4からの返答で提供されたコードについて、以下に完全な形で示します。
Terraformコード
provider "aws" { region = "ap-northeast-1" } resource "aws_s3_bucket" "my_bucket" { bucket = "my-s3-bucket-name" acl = "private" } resource "aws_cloudfront_origin_access_identity" "example" { comment = "example" } resource "aws_cloudfront_distribution" "s3_distribution" { origin { domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name origin_id = "myS3Origin" s3_origin_config { origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path } } enabled = true is_ipv6_enabled = true comment = "S3 bucket distribution" default_root_object = "index.html" default_cache_behavior { allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] target_origin_id = "myS3Origin" forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "allow-all" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } price_class = "PriceClass_100" restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { cloudfront_default_certificate = true } } resource "aws_s3_bucket_policy" "bucket_policy" { bucket = aws_s3_bucket.my_bucket.id policy = jsonencode({ Version = "2012-10-17", Statement = [ { Effect = "Allow", Principal = { AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.example.id}" }, Action = "s3:GetObject", Resource = "arn:aws:s3:::${aws_s3_bucket.my_bucket.bucket}/*", } ] }) }
コード検証
返答されたTerraformコードについて、実際にAWS上でデプロイできるか確認します。
この場合では、GPT-4では明示されていませんが、S3バケットの名前が一意になるように変更します。
Terraformコード(修正後)
provider "aws" { region = "ap-northeast-1" } resource "aws_s3_bucket" "my_bucket" { bucket = "chatgpt-static-website-hosting-bucket-<AWS ID>" acl = "private" } resource "aws_cloudfront_origin_access_identity" "example" { comment = "example" } resource "aws_cloudfront_distribution" "s3_distribution" { origin { domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name origin_id = "myS3Origin" s3_origin_config { origin_access_identity = aws_cloudfront_origin_access_identity.example.cloudfront_access_identity_path } } enabled = true is_ipv6_enabled = true comment = "S3 bucket distribution" default_root_object = "index.html" default_cache_behavior { allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] target_origin_id = "myS3Origin" forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "allow-all" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } price_class = "PriceClass_100" restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { cloudfront_default_certificate = true } } resource "aws_s3_bucket_policy" "bucket_policy" { bucket = aws_s3_bucket.my_bucket.id policy = jsonencode({ Version = "2012-10-17", Statement = [ { Effect = "Allow", Principal = { AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.example.id}" }, Action = "s3:GetObject", Resource = "arn:aws:s3:::${aws_s3_bucket.my_bucket.bucket}/*", } ] }) }
このTerraformコードをデプロイした結果をターミナルで確認すると、想定通りのリソースが作成されている事が分かります。
$ terraform state list aws_cloudfront_distribution.s3_distribution aws_cloudfront_origin_access_identity.example aws_s3_bucket.my_bucket aws_s3_bucket_policy.bucket_policy
この場合も想定通りにIaCコードを生成してくれた一方で、2022年1月までの情報しか持っていないGPT-4はCloudFrontのOrigin Access Controlの設定に対応できない等の点もあり、あと一歩というような感じですかね。
パターン③:サーバレス構成図をCDKv2(TypeScript)に変換
最後に構成図をCDKに変換できるか試してみます。
質問内容
以下のようなHTTPAPIを用いたサーバレスCRUD構成図とメッセージをGPT-4に流した際に、どのようなCDKコードが返ってくるか確認してみます。
- 構成図
- メッセージ
この構成図をデプロイするCDKv2(TypeScript)コードを作成してください。ただし、テンプレートは3000トークンを超えたら分割し、私が「続き」と入力したら続きの回答を投稿してください。
GPT-4からの返答
GPT-4からの返答で提供されたコードについて、以下に完全な形で示します。
CDKコード
import { Stack, StackProps, Construct } from 'aws-cdk-lib'; import { aws_lambda as lambda, aws_lambda_nodejs as nodejs } from 'aws-cdk-lib'; import { aws_apigatewayv2 as apigateway } from 'aws-cdk-lib'; import { aws_dynamodb as dynamodb } from 'aws-cdk-lib'; export class MyStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // DynamoDBテーブルの作成 const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, removalPolicy: cdk.RemovalPolicy.DESTROY // 本番環境ではこの行は削除してください }); // Lambda関数の作成 const lambdaFunction = new nodejs.NodejsFunction(this, 'LambdaFunction', { runtime: lambda.Runtime.NODEJS_14_X, handler: 'handler', entry: 'path_to_your_lambda_file/index.ts', // Lambda関数のファイルパスを指定 environment: { TABLE_NAME: table.tableName }, }); // Lambda関数へのDynamoDBテーブルのアクセス権を付与 table.grantReadWriteData(lambdaFunction); // API Gatewayの作成 const api = new apigateway.HttpApi(this, 'API'); api.addRoutes({ path: '/', methods: [ apigateway.HttpMethod.GET, apigateway.HttpMethod.POST ], integration: new apigateway.LambdaProxyIntegration({ handler: lambdaFunction, }), }); } }
コード検証
返答されたCDKコードについて、実際にAWS上でデプロイできるか確認します。
この場合、aws-cdk-lib.aws_apigatewayv2
をコードそのままで使用しようとするとエラーが起きるため、該当箇所を@aws-cdk/aws-apigatewayv2-alpha
及び@aws-cdk/aws-apigatewayv2-integrations-alpha
に置き換えます。
またNode.jsのバージョンについても、NODEJS_14_X
は近々非推奨化されるため、NODEJS_18_X
に変更します。
CDKコード(修正後)
import { Stack, StackProps, RemovalPolicy } from 'aws-cdk-lib'; import { aws_lambda as lambda, aws_lambda_nodejs as nodejs } from 'aws-cdk-lib'; import { HttpApi, HttpMethod } from '@aws-cdk/aws-apigatewayv2-alpha'; import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations-alpha'; import { aws_dynamodb as dynamodb } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class MyStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // DynamoDBテーブルの作成 const table = new dynamodb.Table(this, 'Table', { partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }, removalPolicy: RemovalPolicy.DESTROY // 本番環境ではこの行は削除してください }); // Lambda関数の作成 const lambdaFunction = new nodejs.NodejsFunction(this, 'LambdaFunction', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'handler', entry: 'lib/index.ts', // Lambda関数のファイルパスを指定 environment: { TABLE_NAME: table.tableName }, }); // Lambda関数へのDynamoDBテーブルのアクセス権を付与 table.grantReadWriteData(lambdaFunction); // API Gatewayの作成 const api = new HttpApi(this, 'API'); api.addRoutes({ path: '/', methods: [ HttpMethod.GET, HttpMethod.POST ], integration: new HttpLambdaIntegration('LambdaIntegration', lambdaFunction), }); } }
このCDKコードをデプロイした結果を(CloudFormation)コンソールで確認すると、想定通りのリソースが作成されている事が分かります。
残念ながら提供されたCDKコードについてはそのまま使えなかったため、いくつかエラーを調査し修正を入れた上でデプロイする事が可能になりました。
最後に
今回はChatGPTの新機能であるGPT-4Vを使って、様々なAWSの構成図を入力し、どこまで正確にIaCコードが生成できるか確認してみました。
きちんと情報が盛り込まれている構成図を入力した場合、体感8-9割方は正確にIaCコードを生成してくれるように感じました。
しかし残りの1-2割程度は、必要な情報が不足していたり、誤っている情報が含まれてしまうため、適宜ユーザ側で補足・修正する必要がありそうです。
さすがに提供されたIaCコードに手を加える事なく利用するのは難しいと感じましたが、それでも構成図だけでIaCコードを推測し生成してくれるのはかなり便利だと思いました。
普段IaCツールを使用してAWSリソースをデプロイしている方は、ぜひ一度GPT-4Vを触ってみてはいかがでしょうか。
以上、つくぼし(tsukuboshi0755)でした!